﻿using System;
using System.Collections.Generic;
using System.Linq;
using Sustainalytics.Entities;
using Sustainalytics.Claims;
using System.Security.Claims;

namespace Sustainalytics.DynamicsCRMGateway
{
    public class FeatureClaimsRepository : ICrmReadOnlyRepository<ClaimMap>
    {
        private string _connectionString;
        private static string _issuer = "Sustainalytics";
        public FeatureClaimsRepository(string connectionString)
        {
            _connectionString = connectionString;
        }

        public IEnumerable<ClaimMap> ReadAll()
        {
            using (var serviceContext = new CrmServiceContextFactory().GetCrmServiceContext(_connectionString))
            {
                var featureQuery = (
                    from f in serviceContext.FeatureSet
                    join cf in serviceContext.FeatureClaimBridgeSet on f.FeatureId equals cf.FeatureId into gr
                    from cf_joined in gr.DefaultIfEmpty()
                    select new
                    {
                        FeatureName = f.Name,
                        FeatureId = f.FeatureId,
                        ClaimId = cf_joined.ClaimId
                    }
               ).AsEnumerable();

                var featureClaimQuery = from f in featureQuery
                                        join c in serviceContext.ClaimSet on f.ClaimId equals c.ClaimId into gr2
                                        from c_joined in gr2.DefaultIfEmpty()
                                        select new
                                        {
                                            FeatureName = f.FeatureName,
                                            FeatureId = f.FeatureId,
                                            ClaimInfo = c_joined == null ? null : new Claim(c_joined.Name, c_joined.Value, ClaimValueTypes.String, _issuer)
                                        };

                var features = featureClaimQuery.ToList();

                // Workaround for avoiding the CRM linq limmitations: 
                // - get the parent features from CRM
                // - filter directLinkedAccountClaim by excluding the parentFeatures with accidental claims (on client side)
                var parentFeatures = (from f_parent in serviceContext.FeatureSet
                                      join f_child in serviceContext.FeatureSet on f_parent.FeatureId equals f_child.ParentFeatureRef.Id
                                      select f_parent.FeatureId.Value).Distinct().ToList();

                // Workaround for avoiding the CRM linq limmitations: 
                // - group by on the client side
                return from ft in features
                       where !parentFeatures.Contains(ft.FeatureId.Value)
                       group ft.ClaimInfo by ft.FeatureName into g
                       select new ClaimMap() { Id = Guid.NewGuid(), Permission = g.Key, Claims = g.Contains(null) ? new List<Claim>() : g.Distinct(new ClaimComparer()).ToList() };
            }
        }
    }
}
